package musika;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.filechooser.FileNameExtensionFilter;

import jm.JMC;
import jm.music.data.*;
import jm.util.Write;

public class Kudeatzailea implements JMC {

	private Artxiboa unekoa;
	private static Kudeatzailea instantzia = new Kudeatzailea();
	private Sequencer midiSeq;
	int aleatorioa1 = 40;
	int aleatorioa2 = 40;
	int emaitza = 0;
	private String artxiboPath;

	private Kudeatzailea() {

		try {
			midiSeq = MidiSystem.getSequencer();
			midiSeq.open();
		} catch (MidiUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	};
/**
 * emaitza aldagaiaren get
 * @return
 */
	public int getEmaitza() {
		return emaitza;
	}
/**
 * Kudeatzailearen instantzia bueltatzen digun get
 * @return
 */
	public static Kudeatzailea getInstantzia() {
		return instantzia;
	}
/**
 * unekoa aldagaiaren get
 * @return
 */
	public Artxiboa getUnekoa() {
		return unekoa;
	}
/**
 * Unekoa aldagaiaren set
 * @param unekoa
 */
	public void setUnekoa(Artxiboa unekoa) {
		this.unekoa = unekoa;
	}
/**
 * Koordenaden arabera, gure nota zein den kalkulatzen duen metodoa
 * @param koord
 * @param modifikadore
 * @return
 */
	public String zeinNota(int koord, int modifikadore) {
		String nota = null;

		if (koord >= 92 + modifikadore) {

			nota = "do";

		} else if (koord <= 91 + modifikadore && koord >= 87 + modifikadore) {
			nota = "re";

		} else if (koord <= 86 + modifikadore && koord >= 81 + modifikadore) {
			nota = "mi";

		} else if (koord <= 80 + modifikadore && koord >= 75 + modifikadore) {
			nota = "fa";

		} else if (koord <= 74 + modifikadore && koord >= 69 + modifikadore) {
			nota = "sol";

		} else if (koord <= 68 + modifikadore && koord >= 64 + modifikadore) {
			nota = "la";

		} else if (koord <= 63 + modifikadore && koord >= 59 + modifikadore) {
			nota = "si";

		}else if (koord <= 58 + modifikadore && koord >= 54 + modifikadore) {
			nota = "do2";

		} else if (koord <= 53 + modifikadore && koord >= 49 + modifikadore) {
			nota = "re2";

		} else if (koord <= 48 + modifikadore && koord >= 42 + modifikadore) {
			nota = "mi2";

		} else if (koord <= 41 + modifikadore && koord >= 37 + modifikadore) {
			nota = "fa2";

		} else if (koord <= 36 + modifikadore && koord >= 31 + modifikadore) {
			nota = "sol2";

		} else if (koord <= 30 + modifikadore && koord >= 25 + modifikadore) {
			nota = "la2";
			} else if (koord <= 24 + modifikadore ) {
				nota = "si2";}

		return nota;

	}
/**
 * Entzun nahi dugun midia sortzeko metodoa
 * @param indize
 */
	public void midiSortu(int indize) {

		Vector<Konpasa> konpasak = getUnekoa().getPentagramak().get(indize)
				.getKonpasak();

		Score s = new Score("Partitura");
		Part inst = new Part("Piano");
		Phrase phrase = new Phrase(0.0); // hasieran hasten da(0,0)
		s.addPart(inst);
		inst.addPhrase(phrase);

		for (int j = 0; j < konpasak.size(); j++) {

			Vector<Nota> k = konpasak.get(j).getNotak();

			for (int h = 0; h < k.size(); h++) {

				Nota n = k.get(h);
				if (n.getNota() == "isilunea") {

					Note n1 = new Note(REST, figuraMidi(n));
					phrase.add(n1);
				} else {

					Note n1 = new Note(notaMidi(n), figuraMidi(n));
					phrase.add(n1);
				}
			}

		}

		s.setTempo(110);
		Write.midi(s, "temp.mid");

	}
/**
 * Datu egiturako nota zein midi nota den kalkulatzeko metodoa
 * @param n
 * @return
 */
	private int notaMidi(Nota n) {

		int emaitza = 0;
		String nota = null;
		nota = n.getNota();

		if (nota.equalsIgnoreCase("do")) {

			emaitza = 60;

		} else if (nota.equalsIgnoreCase("re")) {

			emaitza = 62;

		} else if (nota.equalsIgnoreCase("mi")) {

			emaitza = 64;

		} else if (nota.equalsIgnoreCase("fa")) {

			emaitza = 65;

		} else if (nota.equalsIgnoreCase("sol")) {

			emaitza = 67;

		} else if (nota.equalsIgnoreCase("la")) {

			emaitza = 69;

		} else if (nota.equalsIgnoreCase("si")) {

			emaitza = 71;

		} else if (nota.equalsIgnoreCase("do2")) {

			emaitza = 72;

		} else if (nota.equalsIgnoreCase("re2")) {

			emaitza = 74;

		} else if (nota.equalsIgnoreCase("mi2")) {

			emaitza = 76;

		} else if (nota.equalsIgnoreCase("fa2")) {

			emaitza = 77;

		} else if (nota.equalsIgnoreCase("sol2")) {

			emaitza = 79;

		} else if (nota.equalsIgnoreCase("la2")) {

			emaitza = 81;

		}else if (nota.equalsIgnoreCase("si2")) {

			emaitza = 83;

		}


		if (n.getAlterazioa() == 2) {

			emaitza = emaitza + 1;

		} else if (n.getAlterazioa() == 1) {

			emaitza = emaitza - 1;

		}

		return emaitza;
	}
/**
 * Datu egiturako nota zein midi figura den kalkulatzeko metodoa
 * @param n
 * @return
 */
	private double figuraMidi(Nota n) {

		double emaitza = 0;
		int luzapena = 0;
		luzapena = n.getLuzapena();

		if (luzapena == 32) {

			emaitza = 4.0;

		} else if (luzapena == 16) {

			emaitza = 2.0;

		} else if (luzapena == 8) {

			emaitza = 1.0;

		} else if (luzapena == 4) {

			emaitza = 0.5;

		} else if (luzapena == 2) {

			emaitza = 0.25;

		} else if (luzapena == 1) {

			emaitza = 0.125;

		}

		return emaitza;
	}
/**
 * midia erreproduzitzeko metodoa
 */
	public void midiEntzun() {

		try {

			File midiFile = new File("temp.mid");

			Sequence secuencia = MidiSystem.getSequence(midiFile);

			midiSeq.setSequence(secuencia);
			midiSeq.start();

			midiFile.deleteOnExit();

		} catch (InvalidMidiDataException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
/**
 * Gordetako artxiboa sortzeko metodoa
 * @param datuak
 */
	public void artxiboaSortu(File datuak) {

		try {

			Vector<Pentagrama> pentagramak = getUnekoa().getPentagramak();

			BufferedWriter bw = new BufferedWriter(new FileWriter(datuak));
			int erritmoa = getUnekoa().getErritmoa();
			String erritm = Integer.toString(erritmoa);

			bw.write(erritm);
			bw.newLine();
			for (int i = 0; i < pentagramak.size(); i++) {

				Vector<Konpasa> konpasak = getUnekoa().getPentagramak().get(i)
						.getKonpasak();

				for (int j = 0; j < konpasak.size(); j++) {

					Vector<Nota> k = konpasak.get(j).getNotak();

					for (int h = 0; h < k.size(); h++) {

						Nota n = k.get(h);
						bw.write(n.getNota() + "," + n.getLuzapena() + ","
								+ n.getAlterazioa());
						bw.newLine();
					}

				}

				bw.write("pentagrama");
				bw.newLine();

			}

			bw.close();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
/**
 * Ireki nahi den artxiboa irakurtzeko metodoa
 * @param datuak
 * @param izena
 * @param ikasle
 */
	public void artxiboaIrakurri(File datuak, String izena, boolean ikasle) {

		try {
			BufferedReader br = new BufferedReader(new FileReader(datuak));
			String linea = br.readLine();
			int erritmoa = Integer.parseInt(linea);

			Artxiboa artx = new Artxiboa(erritmoa);
			setUnekoa(artx);
			artx.getPentagramak().get(0).setEmaitzaDa(false);

			EI_Irakasle interfaze1 = null;
			EI_Ikasle interfaze2 = null;

			if (ikasle == true) {
				EI_Ikasle inter = new EI_Ikasle();
				inter.getFrmMusikebal().setTitle("MusikEbal - " + izena);

				interfaze2 = inter;

			} else {
				EI_Irakasle inter = new EI_Irakasle();
				inter.getFrmMusikebal().setTitle("MusikEbal - " + izena);
				interfaze1 = inter;
			}

			linea = br.readLine();

			int i = 0;
			int h = 0;

			h = aleatorioaSortu(i);

			while (linea != null) {
				if (linea.equalsIgnoreCase("pentagrama")) {
					
					if (ikasle == true) {
						
						interfaze2.bukaeraMarra(h);

					}

					i++;

					h = aleatorioaSortu(i);

				} else {

					int j = 0;
					String notaIzen = null;
					int luzapena = 0;
					int alterazioa = 0;
					StringTokenizer st = new StringTokenizer(linea, ",");
					while (st.hasMoreTokens()) {
						if (j == 0) {

							notaIzen = st.nextToken();

						} else if (j == 1) {

							luzapena = Integer.parseInt(st.nextToken());

						} else if (j == 2) {

							alterazioa = Integer.parseInt(st.nextToken());

						}

						j++;

					}

					Nota nota = new Nota(notaIzen, luzapena, alterazioa);

					if (ikasle == false) {
						Konpasa konp = getUnekoa().getPentagramak().get(i)
								.getKonpasak().lastElement();

						interfaze1.notaMargotuKargatzean(i, konp, nota);

					} else {
						Konpasa konp = getUnekoa().getPentagramak().get(h)
								.getKonpasak().lastElement();

						interfaze2.notaMargotuKargatzean(h, konp, nota);

					}

				}

				linea = br.readLine();
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
/**
 * Irakurri metodoak behar duen aleatorio algoritmoa
 * @param max
 * @param min
 * @return
 */
	public static int aleatorio(int max, int min) {
		return (int) (Math.random() * (max - min)) + min;
	}
/**
 * Aleatorio algoritmoa erabiliz, nahi dugun emaitza sortzen duen metodoa. Ikaslearen interfazean konpasak aleatorioki agertzeko balio du
 * @param i
 * @return
 */
	private int aleatorioaSortu(int i) {
		int h = 0;

		if (i == 0) {
			int i1 = aleatorio(3, 0);
			aleatorioa1 = i1;

			h = i1;

			getUnekoa().getPentagramak().get(h).setEmaitzaDa(true);
			emaitza = h;

		} else if (i == 1) {

			int i1 = aleatorio(3, 0);
			while (i1 == aleatorioa1) {

				i1 = aleatorio(3, 0);

			}

			aleatorioa2 = i1;
			h = i1;

		} else if (i == 2) {

			int i1 = aleatorio(3, 0);
			while (i1 == aleatorioa1 || i1 == aleatorioa2) {

				i1 = aleatorio(3, 0);

			}

			h = i1;

		}
		return h;
	}
/**
 * Artxiboa gordetzeko metodoa
 * @return
 */
	public String artxiboaGorde() {

		JFileChooser fc = new JFileChooser();
		fc.setAcceptAllFileFilterUsed(false);
		FileNameExtensionFilter filter = new FileNameExtensionFilter(
				"MusikEbal artxiboak", "mke");
		fc.addChoosableFileFilter(filter);
		int aukera = fc.showSaveDialog(fc);
		String izena = null;

		if (aukera == JFileChooser.APPROVE_OPTION) {
			String artxiboIzena = fc.getSelectedFile().getName();
			izena = artxiboIzena;
			if (artxiboIzena.contains(".mke")) {
				String filePath = fc.getSelectedFile().getAbsoluteFile() + "";
				File datuak = new File(filePath);
				artxiboaSortu(datuak);
			} else {
				String filePath = fc.getSelectedFile().getAbsoluteFile()
						+ ".mke";
				artxiboPath = filePath;
				File datuak = new File(filePath);
				artxiboaSortu(datuak);
			}
			
			getUnekoa().setAldatuta(false);

		} else if (aukera == JFileChooser.CANCEL_OPTION) {

			izena = "izenbururik gabeko artxiboa";

		}
		return izena;
	}
/**
 * Artxiboa irekitzeko metodoa
 * @param ikasle
 * @return
 */
	public String artxiboaIreki(boolean ikasle) {

		JFileChooser fc = new JFileChooser();
		fc.setAcceptAllFileFilterUsed(false);
		FileNameExtensionFilter filter = new FileNameExtensionFilter(
				"MusikEbal artxiboak", "mke");
		fc.addChoosableFileFilter(filter);
		int aukera = fc.showOpenDialog(fc);

		if (aukera == JFileChooser.APPROVE_OPTION) {

			File datuak = fc.getSelectedFile();
			String filePath = fc.getSelectedFile().getAbsoluteFile()
			+ "";
			artxiboPath = filePath;
			artxiboaIrakurri(datuak, fc.getSelectedFile().getName(), ikasle);
		}else if (aukera == JFileChooser.CANCEL_OPTION) {

			fc.setVisible(false);

		}
		return fc.getSelectedFile().getName();
	}
/**
 * Artxibopath aldagaiaren get
 * @return
 */
	public String getArtxiboPath() {
		return artxiboPath;
	}
/**
 * Artxibopath aldagaiaren set
 * @param artxiboPath
 */
	public void setArtxiboPath(String artxiboPath) {
		this.artxiboPath = artxiboPath;
	}
}
